package system

import (
	"context"
	"fmt"
	"private-domain-overseas-service/app/business/api/internal/repository/system"
	"private-domain-overseas-service/pkg/common"
	"private-domain-overseas-service/pkg/constant"
	"private-domain-overseas-service/pkg/sms"
	"private-domain-overseas-service/pkg/status/bizsystemsmsrecord"
	"private-domain-overseas-service/pkg/xerr"
	"private-domain-overseas-service/tools/ent"
	"private-domain-overseas-service/tools/ent/hzsystemsmsrecord"
	"private-domain-overseas-service/tools/ent/predicate"
	"time"

	"private-domain-overseas-service/app/business/api/internal/svc"
	"private-domain-overseas-service/app/business/api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type SystemSmsCaptchaLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// NewSystemSmsCaptchaLogic - 发送验证码
func NewSystemSmsCaptchaLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SystemSmsCaptchaLogic {
	return &SystemSmsCaptchaLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *SystemSmsCaptchaLogic) SystemSmsCaptcha(req *types.SystemSmsCaptchaRequest) error {
	// 创建实例
	captchaDao := system.NewSystemSmsRecordDao(l.ctx, l.svcCtx)

	//判断是否人机校验(如果有密钥验证并通过，没有则正常校验)
	if len(req.SystemSmsVerify) > 0 {
		// 拼接md5（手机号+区号+#2025*hz(b..H|y!）
		md5Verify := common.GenerateMD5(fmt.Sprintf("%s%s#2025*hz(b..H|y!", req.SystemSmsPhone, req.SystemSmsArea))
		// 验证秘钥是否一致
		if req.SystemSmsVerify != md5Verify {
			if l.handlerHumanCheck(req.SystemSmsArea, req.SystemSmsPhone) {
				return xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, "验证失败")
			}
		}
	} else {
		if l.handlerHumanCheck(req.SystemSmsArea, req.SystemSmsPhone) {
			return xerr.ErrCodeMsg(xerr.ServerApiVerificationPromptError, "验证提示")
		}
	}

	// 生成4位随机验证码
	captchaCode := common.GenerateCaptcha()
	var (
		msg string
	)

	// 组装验证码数据
	captchaCreate := &ent.HzSystemSmsRecord{
		SystemSmsArea:     req.SystemSmsArea,
		SystemSmsPhone:    req.SystemSmsPhone,
		SystemSmsCaptcha:  captchaCode,
		SystemSmsType:     bizsystemsmsrecord.SmsPlatformApp,
		SystemSmsPlatform: bizsystemsmsrecord.SmsTypeCaptcha,
		SystemSmsStatus:   bizsystemsmsrecord.SmsStatusUnUse,
		SystemSmsSendAt:   time.Now().Unix(),
		SystemSmsExpireAt: time.Now().Add(15 * time.Minute).Unix(),
		CreatedAt:         time.Now().Unix(),
		UpdateAt:          time.Now().Unix(),
	}

	// 区分不同的区号
	if req.SystemSmsArea == constant.ChinaAreaCode {
		// 生成华瑞云短信
		hry, _ := sms.NewHrySmsService()
		//tencent, _ := sms.NewTencentSmsService()
		msg = fmt.Sprintf("【慧赚生活】%s为您的登录验证码，请于15分钟内填写，如非本人操作，请忽略本短信。", captchaCode)

		// 验证码存入数据库
		captchaCreate.SystemSmsMessage = msg
		captchaCreate.SystemSmsDescription = msg
		smsCreateRes, err := captchaDao.SystemSmsRecordCreate(captchaCreate, nil)
		if err != nil {
			return xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("验证码存入数据库失败 %s", err.Error()))
		}

		// 发送短信
		err = hry.SendMessage(req.SystemSmsPhone, msg, l.svcCtx.Config.Env)
		//err = tencent.Send(req.SystemSmsPhone, captchaCode)
		if err != nil {
			// 修改验证码状态为发送失败
			errSend := l.handlerUpdateSystemSmsRecordStatus(smsCreateRes.ID)
			if errSend != nil {
				return xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("发送短信失败:%s,修改验证码状态为发送失败 失败%s", err.Error(), errSend.Error()))
			}
		}
	} else {
		globe, _ := sms.NewGlobeSmsService()
		// 默认繁体中文文案
		msg = fmt.Sprintf(constant.ZHHantMsg, captchaCode)
		// 如果区号不为香港台湾澳门，则发送海外文案
		if req.SystemSmsArea != constant.TaiwanAreaCode && req.SystemSmsArea != constant.MacaoAreaCode && req.SystemSmsArea != constant.HongKongAreaCode {
			// 英文文案
			msg = fmt.Sprintf(constant.EnMsg, captchaCode)
		}

		// 验证码存入数据库
		captchaCreate.SystemSmsMessage = msg
		captchaCreate.SystemSmsDescription = msg
		smsCreateRes, err := captchaDao.SystemSmsRecordCreate(captchaCreate, nil)
		if err != nil {
			return xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("验证码存入数据库失败%s", err.Error()))
		}

		// 发送海外短信
		err = globe.GlobeSendMessage(req.SystemSmsArea+req.SystemSmsPhone, msg, l.svcCtx.Config.Env)
		if err != nil {
			// 修改验证码状态为发送失败
			errSend := l.handlerUpdateSystemSmsRecordStatus(smsCreateRes.ID)
			if errSend != nil {
				return xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("发送短信失败:%s,修改验证码状态为发送失败 失败%s", err.Error(), errSend.Error()))
			}
		}
	}

	return nil
}

// handlerHumanCheck - 处理人机校验
func (l *SystemSmsCaptchaLogic) handlerHumanCheck(areaCode, phone string) bool {
	captchaDao := system.NewSystemSmsRecordDao(l.ctx, l.svcCtx)
	now := time.Now()

	// 凌晨1:00-5:00发起登录 直接通过校验（不需要人机验证）
	if now.Hour() >= 1 && now.Hour() < 5 {
		return false
	}
	// 15分钟免验（直接通过）
	if firstKey, _ := l.svcCtx.BizRedis.Get(fmt.Sprintf(constant.HzAppLoginCheckFirstKey, areaCode, phone)); firstKey != "" {
		return false
	}
	// 5分钟免验（需要人机验证）
	if key, _ := l.svcCtx.BizRedis.Get(fmt.Sprintf(constant.HzAppLoginCheckKey, areaCode, phone)); key != "" {
		return true
	}

	// 检查5分钟内短信请求次数
	fiveMinutesAgo := now.Add(-5 * time.Minute).Unix()
	conditions := []predicate.HzSystemSmsRecord{
		hzsystemsmsrecord.SystemSmsAreaEQ(areaCode),
		hzsystemsmsrecord.SystemSmsPhoneEQ(phone),
		hzsystemsmsrecord.CreatedAtGTE(fiveMinutesAgo),
		hzsystemsmsrecord.CreatedAtLTE(now.Unix()),
	}
	count, _ := captchaDao.SystemSmsRecordConditionsCount(conditions)

	// 同手机号5分钟内请求≥3次：需要设置免验并返回结果
	if count >= 3 {
		// 检查是否已存在首次免验标记
		if checkKey, _ := l.svcCtx.BizRedis.Get(fmt.Sprintf(constant.HzAppLoginCheckFirstKey, areaCode, phone)); checkKey != "" {
			// 已触发过首次，设置5分钟免验
			l.svcCtx.BizRedis.SetexCtx(l.ctx, fmt.Sprintf(constant.HzAppLoginCheckKey, areaCode, phone), "1", 5*60)
		} else {
			// 首次触发，设置15分钟免验
			l.svcCtx.BizRedis.SetexCtx(l.ctx, fmt.Sprintf(constant.HzAppLoginCheckFirstKey, areaCode, phone), "1", 15*60)
		}
		return false // 触发免验机制，不需要人机验证
	}

	// 默认情况：请求次数未达阈值，需要人机验证
	return true
}

// handlerUpdateSystemSmsRecordStatus - 修改验证码状态为发送失败
func (l *SystemSmsCaptchaLogic) handlerUpdateSystemSmsRecordStatus(ID int) error {
	// 创建实例
	captchaDao := system.NewSystemSmsRecordDao(l.ctx, l.svcCtx)

	// 组装参数
	smsUpdateStatusConditions := make([]predicate.HzSystemSmsRecord, 0)
	smsUpdateStatusConditions = append(smsUpdateStatusConditions, hzsystemsmsrecord.IDEQ(ID))
	captchaUpdateStatus := &ent.HzSystemSmsRecord{
		SystemSmsStatus: bizsystemsmsrecord.SmsSendFail,
		UpdateAt:        time.Now().Unix(),
	}

	// 修改数据库
	err := captchaDao.SystemSmsRecordUpdateStatusByConditions(smsUpdateStatusConditions, captchaUpdateStatus, nil)
	if err != nil {
		fmt.Printf("修改验证码状态失败%s", err.Error())
		return err
	}

	return nil
}
